#pragma once 
#include<iostream>
#include<sys/types.h>
#include<unistd.h>
#include<ctime>
#include<cstdarg>
#include<fstream>
#include<cstring>
#include<pthread.h>
#include"LockGuard.hpp"
namespace log_ns
{

enum 
{
    DEBUG=1,//调试
    INFO,//输出成功
    WARNING,//警告可跑
    ERROR,//错误可跑
    FATAL//致命的不可跑
};


class logmessage 
{
public:
    std::string  _level;
    pid_t _id;
    std::string  _filename;
    int _filenumber;
    std::string _curr_time;
    std::string _message_info;

};
std::string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
    return "DEBUG";
    case INFO:
    return "INFO";  
    case WARNING:
    return "WAARNING";
    case ERROR:
    return "ERROR";
    case FATAL:
    return "FATAL";
    
    default:
    return "UNKNOW";
        break;
    }
}
std::string GetCurTime()
{
        time_t now =time (nullptr);//当前时间
        // std::cout<<"now"<<now<<std::endl;
        //localtime() 将时间戳转化为现实时间
        struct tm *curr_time =localtime(&now);
        char buffer[128];
        snprintf(buffer,sizeof(buffer),"%d-%d-%d %d:%d:%d0",\
                curr_time->tm_year+1900,
                curr_time->tm_mon+1,
                curr_time->tm_mday,
                curr_time->tm_hour,
                curr_time->tm_min,
                curr_time->tm_sec);
        return buffer;

}




#define SCREEN_TYPE 1 //向显示器打印
#define FILE_TYPE  2  //向文件打印

//log.logmessage("",12,INFO,"this is a%d message",x);
const std::string glogfile="./log.txt";
pthread_mutex_t glock=PTHREAD_MUTEX_INITIALIZER;
class Log
{
public:
    Log(const std::string &logfile=glogfile):_logfile(logfile),_type(SCREEN_TYPE)
    {

    }

    void Enable (int type)
    {
        _type=type;

    }
        
    void FlushLogToScreen(logmessage lg)
    {
        //[日志等级][pid][filename][filenumber][time] 日志内容(支持可変参数)

        printf("[%s][%d][%s][%d][%s]%s",
                    lg._level.c_str(),
                    lg._id,
                    lg._filename.c_str(),
                    lg._filenumber,
                    lg._curr_time.c_str(),
                    lg._message_info.c_str());

    }
    void FlushLogToFile(logmessage lg)
    {
        std::ofstream out(_logfile,std::ios::app);//这里要改为a
        if(!out.is_open())
        
            return ;
       
        char logtxt[2048];
        snprintf(logtxt,sizeof(logtxt),"[%s][%d][%s][%d][%s]%s",
                    lg._level.c_str(),
                    lg._id,
                    lg._filename.c_str(),
                    lg._filenumber,
                    lg._curr_time.c_str(),
                    lg._message_info.c_str());
   
        out.write(logtxt,strlen(logtxt));
        
        out.close();

    }
    void FlushLog(const logmessage &lg)
    {   //加过滤逻辑
        LockGuard lockguard(&glock);
        switch(_type)
        {
            case SCREEN_TYPE:
                FlushLogToScreen(lg);
                break;
            case FILE_TYPE:
            FlushLogToFile(lg);
                break;
        }
    }
    void logMessage(std :: string filename , int filenumber ,int level, const char* format,...)//这里的format是格式，...是c的可变参数
    {
        logmessage lg;
        lg._level=LevelToString(level);
        lg._id=getpid();
        lg._filename=filename;
        lg._filenumber=filenumber;
        lg._curr_time=GetCurTime();    //gettimeofday  接口   系统       #include<ctime>   time_t time()
        // va_list;
        //#include<cstdarg>
        //vsnprintf()
        // void P（int num,...)
        // {
        //     va_list  ap;这里的valist是一个宏就是一个指针
        //     va_start(ap,num);这里就是把ap这个指针指向可变参数最近的参数//这里的ap是可以直接指向可变区的原因：因为参数的传递是从右向左传递而且是连续的所以传一个最近参数的指针就可以直接找到的可变参数的地址
        //     这里是依靠参数加num跳到可变参数
        //     for(int i=0;i<num;i++)
        //     {
        //         int n=va_arg(ap,int);
        //         printf("%d",a);
        //     }
        //     va_end(ap);
        // }
        //vsnprintf()将可变参数的内容传递到指定空间
        va_list ap;
        va_start(ap,format);
        char log_info [1024];
        vsnprintf(log_info,sizeof(log_info),format,ap);//这里的ap是给可变的地址，format是格式化
        va_end(ap);
        lg._message_info=log_info;
        //刷新日志
        FlushLog(lg);
    }
    ~Log()
    {

    }
private:
     int _type;
     std::string _logfile;

};
Log lg;
//这里是一个可以传递可变参数的宏函数，这里的__FILE__是文件名的宏在函数使用的文件可以直接将自己的文件名替代这个位置，//
// __LEVEL__这个是行号这里会把使用这个函数的行号替代成这个位置，
//_VA_ARGS_是一个可变参数的宏这里会传递的可变参数替代到这里
//这里##是可以将将——VA_ARGS这个参数就是没有可变参数时可以省略
#define LOG(Level, Format,...)do{lg.logMessage(__FILE__,__LINE__,Level,Format,##__VA_ARGS__);}while(0)
#define EnableScrean()do{lg.Enable(SCREEN_TYPE);}while(0)
#define EnableFILE()do{lg.Enable(FILE_TYPE);}while(0)
}
